use std::fs::File;

use serde_json;

use crate::domain::entities::Item;

/// Operation result
pub enum OpResult {
    Success,
    Fail,
    NotFound,
}

pub trait Medicine: Send + Sync {
    fn add(&mut self, item: Item) -> OpResult;
    fn find(&self, name: String) -> Vec<Item>;
    fn list(&self) -> Vec<Item>;
    fn update_quantity(&mut self, id: u32, quantity: u32) -> OpResult;
}

#[derive(Debug)]
pub struct InMemoryRepo {
    items: Vec<Item>,
}

impl InMemoryRepo {
    pub fn new() -> Self {
        InMemoryRepo { items: vec![] }
    }

    #[allow(dead_code)]
    fn find_by_id(&self, id: u32) -> Option<Item> {
        for it in self.items.iter() {
            if it.id == id {
                return Some(it.clone());
            }
        }
        None
    }
}

fn trim_date(d: String) -> String {
    let list: Vec<&str> = d.as_str().split("T").collect();
    return String::from(list[0]);
}

impl Medicine for InMemoryRepo {
    fn add(&mut self, mut item: Item) -> OpResult {

        let f = File::open("data.json").unwrap();
        let mut items: Vec<Item> = serde_json::from_reader(f).unwrap();
        let mut new_id: u32 = 1;
        if items.len() >= 1 {
            items.sort_by(|a, b| a.id.cmp(&b.id));
            new_id = items.last().unwrap().id + 1;
        }
        item.bought_date = trim_date(item.bought_date.clone());
        item.made_date = trim_date(item.made_date.clone());
        let mut found: bool = false;
        for it in items.iter_mut() {
            if it.id == item.id {
                found = true;
                if item.name != "" {
                    it.name = item.name.clone();
                }
                if item.price != 0.0_f32 {
                    it.price = item.price;
                }
                if item.made_date != "" {
                    it.made_date = item.made_date.clone();
                }
                it.quantity = item.quantity;
                if item.usage != "" {
                    it.usage = item.usage.clone();
                }
                if item.bought_from != "" {
                    it.bought_from = item.bought_from.clone();
                }
                if item.bought_date != "" {
                    it.bought_date = item.bought_date.clone();
                }
                if item.brand != "" {
                    it.brand = item.brand.clone();
                }
                if item.effect_months != 0_u16 {
                    it.effect_months = item.effect_months;
                }
                if item.location != "" {
                    it.location = item.location.clone();
                }
                if item.log != "" {
                    it.log = item.log.clone();
                }
                if item.picture != "" {
                    it.picture = item.picture.clone();
                }
                if item.barcode != "" {
                    it.barcode = item.barcode.clone();
                }
                break;
            }
        }
        if ! found {
            item.id = new_id;
            items.push(item);
        }
        let writer = File::create("data.json").unwrap();
        serde_json::to_writer_pretty(writer, &items).unwrap();

        OpResult::Success
    }

    fn find(&self, name: String) -> Vec<Item> {
        let mut res = vec![];
        for it in self.items.iter() {
            if it.name == name {
                res.push(it.clone());
            }
        }

        res
    }

    fn list(&self) -> Vec<Item> {
        let f = File::open("data.json").unwrap();
        let mut items: Vec<Item> = serde_json::from_reader(f).unwrap();
        for it in items.iter_mut() {
            it.update();
        }
        items
    }

    fn update_quantity(&mut self, id: u32, quantity: u32) -> OpResult {
        let f = File::open("data.json").unwrap();
        let mut items: Vec<Item> = serde_json::from_reader(f).unwrap();
        println!("id: updating: {}", id);
        for it in items.iter_mut() {
            if it.id == id {
                it.quantity = quantity;
                break;
            }
        }
        let writer = File::create("data.json").unwrap();
        serde_json::to_writer_pretty(writer, &items).unwrap();
        OpResult::Success
    }
}

#[test]
fn it_should_basic() {
    let item = Item {
        id: 1,
        name: String::from("感康"),
        price: 8.5,
        made_date: String::from("2021-09-23"),
        quantity: 20,
        location: String::from("家"),
        usage: String::from("感冒"),
        bought_from: String::from("医院"),
        bought_date: String::from("2021-09-23"),
        brand: String::from("得菲尔"),
        expired: false,
        effect_months: 24,
    };

    let mut repo = InMemoryRepo::new();

    let mut res = repo.add(item.clone());
    res = repo.add(item.clone());
    res = repo.add(item.clone());
    println!("rep: {:?}", repo);

    let items = repo.find(String::from("感康"));

    assert_eq!(items.len(), 3);
}
